﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DecisionFramework.ServiceProtection
{
    /// <summary>
    /// Represents a base implementation of the service protector
    /// interface.
    /// </summary>
    public class ServiceProtectorBase : IServiceProtector
    {
        /// <summary>
        /// Whether or not the service operations should be performed.
        /// </summary>
        protected bool ShouldPerform = true;

        /// <summary>
        /// The mechanisms will need this security token to determine
        /// authentication and authorization. 
        /// </summary>
        public string SecurityToken { get; set; }

        /// <summary>
        /// Specifies that the service will require a valid given
        /// security token in order to continue processing.
        /// </summary>
        /// <param name="securityToken">The security token to check validity.</param>
        /// <returns>This for fluent interface.</returns>
        public virtual IServiceProtector RequiresValidSecurityToken(string securityToken)
        {
            SecurityToken = securityToken;

            if (!IsValidSecurityToken(SecurityToken))
            {
                ShouldPerform = false;
                ReportInvalidSecurityToken(securityToken);
            }

            return this;
        }

        protected virtual bool IsValidSecurityToken(string securityToken)
        {
            return false;
        }

        protected virtual void ReportInvalidSecurityToken(string securityToken)
        {
        }

        /// <summary>
        /// Specifies that the principal associated with the security token
        /// will need the authorization action for the given optional toObject.
        /// </summary>
        /// <param name="action">The authorization action that performs the check.</param>
        /// <param name="toObject">Action will check access to this, optional, object.</param>
        /// <returns>This for fluent interface.</returns>
        public virtual IServiceProtector AndAuthorizedTo(IAuthorizationAction action, object toObject)
        {
            if (ShouldPerform && !action.IsAuthorizedFor(SecurityToken, toObject))
            {
                ShouldPerform = false;
                ReportNotAuthorizedForActionTo(action, toObject);
            }
            return this;
        }

        protected virtual void ReportNotAuthorizedForActionTo(IAuthorizationAction action, object toObject)
        {
        }

        /// <summary>
        /// Specifies that the principal associated with the given security token 
        /// will need to be of the level of the given role type.
        /// </summary>
        /// <param name="roleType">The role type level required.</param>
        /// <returns>This for fluent interface.</returns>
        public virtual IServiceProtector AndRequiresRoleType(RoleType roleType)
        {
            if (ShouldPerform && roleType > GetRoleTypeFor(SecurityToken))
            {
                ShouldPerform = false;
                ReportRequiresRoleType(roleType);
            }

            return this;
        }

        protected virtual void ReportRequiresRoleType(RoleType roleType)
        {
        }

        protected virtual RoleType GetRoleTypeFor(string securityToken)
        {
            return RoleType.ContactOnly;
        }

        /// <summary>
        /// All other statements must be true in order to perform
        /// the given service action (block of code).
        /// </summary>
        /// <param name="action">The service action (block of code).</param>
        public virtual void InOrderToPerform(Action action)
        {
            if (ShouldPerform)
                action.Invoke();
        }
    }
}
